package com.szwistar.common.comm.jsonrpc;

/**
 * JSON-RPC 端点(即 JsonRpc 的通信的单端)
 *
 * <h1>一个端点既可以做为“客户端”也可以做为“服务端”，在不同角色情况下，有以下功能：</h1>
 * <li>做为客户端：向服务端发起 调用(JsonRpcMessageCall) 并 接收对端的返回值(JsonRpcMessageReturn)
 * <li>做为客户端：向服务端订阅要监听的消息通知主题
 * <li>做为客户端：接收服务端消息通知(JsonRpcMessageNotify)<br>
 * <br>
 * <li>做为服务端：接受客户端的调用请求(JsonRpcMessageCall) 并 返回值(JsonRpcMessageReturn)
 * <li>做为服务端：接受客户端的消息订阅，并保存
 * <li>做为服务端：向订阅了消息通知的客户端发送消息通知
 *
 * <h1>可以有不同的底层实现，目前已经实现的协议有：</h1>
 * <li>JsonRpc@MQTT: MP2MP/多点对多点、双向调用、双向消息通知
 * <li>JsonRpc@WebSocket/TCP/UDP：P2MP/点对多点(Server -> *Client)、单向调用(Client -> Server)、双向消息通知
 * <li>JsonRpc@HTTP：P2MP/点对多点(Server -> *Client)、单向调用(Client -> Server)、单向消息通知(Client -> Server)
 * <li>JsonRpc@WebHost: P2P/点对点(WebHost <-> Web页面)、单向调用(Web页面 -> WebHost)、单向消息通知(Web页面 -> WebHost)
 *
 * <h1>JsonRpc 消息订阅遵守与 MQTT 相同的主题匹配规则:</h1>
 * @see JsonRpcEndpointAbstract#filterTopic(String, String)
 */
public interface JsonRpcEndpoint {
	/**
	 * 把 obj 中符合 JsonRpc API 和 Notify 接口的函数注册为名为 name 的服务接口
	 * @param name 服务名
	 * @param obj 提供服务的对象
	 */
	public void registerService(String name, Object obj);

	/**
	 * (本端内部处理)注册服务
	 * @param service 服务提供者，service中所有以下类型函数将被注册为服务函数：
	 * 	RPC 调用函数: JsonRpcResponseMessage service.xxx(JsonRpcRequestMessage request);
	 * 	RPC 事件通知处理函数: void service.xxx(JsonRpcNotifyMessage request);
	 */
	public void registerService(JsonRpcService service);

	/**
	 * 是否已连接
	 */
	boolean isConnected();

	/**
	 * 主动关闭本客户端连接
	 */
	void close();

	/**
	 * (本端内部处理)绑定到通信连接，并开始监听请求、接受通知
	 * @param linkObj 用于通信的连接对象<br>
	 * 		<li>对于 MqttJsonRpcEndpointImpl 就是 MqttClient</li>
	 * @param caller 我自己的监听地址<br>
	 * 		<li>对于 MqttJsonRpcEndpointImpl 就是我的本地监听 topic</li>
	 * @throws Exception
	 */
	public void listenOn(Object linkObj, String caller) throws Exception;

	/**
	 * (对端->本端)当接收到外部的消息处理
	 * @param message
	 */
	public void onMessageReceived(JsonRpcMessage message);

	/**
	 * (本端->对端)发送消息
	 * @param target 要发送的目标。一般来说收到的消息中的 from 字段可以做为要发送的目标。
	 * @param message 要发送的消息
	 * @param qos 消息 QOS
	 * @param timeout 等待时间(ms)，<=0 时表示不等待返回结果，也不会进行超时重发！
	 * @return 标准错误消息
	 */
	public JsonRpcMessage send(String target, JsonRpcMessage message, int timeout, int qos);

	/**
	 * (本端->对端)发送RPC请求并等待返回
	 * @param target 要调用的目标
	 * @param token 权限认证令牌
	 * @param method 要调用的方法名
	 * @param params 方法的JSON格式的参数字符串；如果不是字符串，则自动转换为 JSON 格式字符串
	 * @param timeout 等待时间(ms)，为0时表示不等待返回结果
	 * @return 标准错误消息
	 * @see #send(String, JsonRpcMessage, int, int)
	 */
	public JsonRpcMessageReturn rpc(String target, String token, String method, Object params, int timeout);

	/**
	 * 处理对端发来的消息订阅请求
	 * @return 标准错误消息
	 */
	public JsonRpcMessageReturn handleSubscribe(JsonRpcMessageCall request);

	/**
	 * 订阅对端的消息通知
	 * @add 要添加订阅的主题列表
	 * @del 要取消订阅的主题列表
	 */
	public JsonRpcMessageReturn subscribe(String target, String token, String[] add, String[] del, int timeout);

	/**
	 * (本端->对端)异步通知，无需对方返回
	 * @param target 要通知的目标
	 * @param token 鉴权 Token
	 * @param method 事件类型
	 * @param params 事件参数
	 * @see #send(String, JsonRpcMessage, int, int)
	 */
	public void notify(String target, String token, String method, Object params);

	/**
	 * (本端->对端)Ping
	 * @param target 要发送的目标
	 */
	public void ping(String target);

	/**
	 * 获取响应延时(ms)：即从发出 ping 消息到收到对端 ack 之间的延迟时间
	 * @param target 对端标识
	 */
	public int getDelay(String target);
}
